#include "stdafx.h"
#include "Timer.h"
#include "Time.h"
#include "TimerEvent.h"
#include "ITimerCallBack.h"
#include <vector>

using namespace unigame;

Timer* Timer::s_instance = 0;

Timer::Timer():
m_inGameTime(0)
{
}

Timer::~Timer()
{
    for(std::list<TimerEvent*>::iterator it = m_list.begin(), end = m_list.end(); it != end; ++it)
    {
        delete *it;
    }
    for(std::list<TimerEvent*>::iterator it = m_realTimeList.begin(), end = m_realTimeList.end(); it != end; ++it)
    {
        delete *it;
    }
    m_list.clear();
    m_realTimeList.clear();
}

void Timer::update()
{
    m_inGameTime += (int64u)(Time::instance()->deltaTime() * 1000);
    checkTimeEvent(m_realTimeList, Time::instance()->currentRunTime());
    checkTimeEvent(m_list, m_inGameTime);
}

void Timer::checkTimeEvent(std::list<TimerEvent*>& list, int64u time)
{
    std::list<TimerEvent*>::iterator it = list.begin();
    for(std::list<TimerEvent*>::iterator end = list.end(); it != end; ++it)
    {
        if(time < (*it)->m_targetTime)
        {
            break;
        }
		else if(!(*it)->m_isDeleted)
        {
			int64u offset = time - (*it)->m_targetTime;
			(*it)->m_callBack->onTimeUp((*it)->m_id, offset / 1000.0f);
            if((*it)->m_loopTime > 0)
            {
				if(offset >= (*it)->m_loopTime)
				{
					int32u multi = (int32u)(offset / (*it)->m_loopTime);
					offset -= (*it)->m_loopTime * multi;
				}
				(*it)->m_nextTime = (int32u)((*it)->m_loopTime - offset);
                registerTimer((*it), list, time);
            }
            else
            {
				(*it)->deleteSelf();
				delete (*it);
            }
        }
		else
		{
			delete (*it);
		}
    }
    list.erase(list.begin(), it);
}

void Timer::registerTimer(TimerEvent *event, std::list<TimerEvent*>& list, int64u time)
{
    event->m_targetTime = event->m_nextTime + time;
    std::list<TimerEvent*>::iterator it = list.begin();
    for(std::list<TimerEvent*>::iterator end = list.end(); it != end; ++it)
    {
        if(event->m_targetTime < (*it)->m_targetTime)
        {
            list.insert(it, event);
            return;
        }
    }
    list.push_back(event);
}

void Timer::registerRealTimeTimer(ITimerCallBack *callBack, float time, float loop, int32u iden)
{
    TimerEvent* e = uni_new TimerEvent((int32u)(time * 1000), callBack, (int32u)(loop * 1000), iden);
    registerTimer(e, m_realTimeList, Time::instance()->currentRunTime());
}

void Timer::registerTimer(ITimerCallBack *callBack, float time, float loop, int32u iden)
{
    TimerEvent* e = uni_new TimerEvent((int32u)(time * 1000), callBack, (int32u)(loop * 1000), iden);
    registerTimer(e, m_list, m_inGameTime);
}

float Timer::removeTimer(ITimerCallBack *callBack, std::list<TimerEvent*>& list, int64u time)
{
    for(std::list<TimerEvent*>::iterator it = list.begin(), end = list.end(); it != end; ++it)
    {
        if((*it)->m_callBack == callBack)
        {
            time = (*it)->m_targetTime - time;
			(*it)->deleteSelf();
            return time / 1000.0f;
        }
    }
    return -1;
}

float Timer::removeTimer(ITimerCallBack *callBack)
{
    return removeTimer(callBack, m_list, m_inGameTime);
}

float Timer::removeRealTimeTimer(ITimerCallBack *callBack)
{
    return removeTimer(callBack, m_realTimeList, Time::instance()->currentRunTime());
}

float Timer::removeTimerById(ITimerCallBack *callBack, int32u iden, std::list<TimerEvent*>& list, int64u time)
{
    for(std::list<TimerEvent*>::iterator it = list.begin(), end = list.end(); it != end; ++it)
    {
        if((*it)->m_callBack == callBack && iden == (*it)->m_id)
        {
            time = (*it)->m_targetTime - time;
			(*it)->deleteSelf();
            return time / 1000.0f;
        }
    }
    return -1;
}

float Timer::removeTimerById(ITimerCallBack *callBack, int32u iden)
{
    return removeTimerById(callBack, iden, m_list, m_inGameTime);
}

float Timer::removeRealTimeTimerById(unigame::ITimerCallBack *callBack, int32u iden)
{
    return removeTimerById(callBack, iden, m_realTimeList, Time::instance()->currentRunTime());
}

void Timer::removeAllTimerOf(ITimerCallBack *callBack, std::list<TimerEvent*>& list)
{
    for(std::list<TimerEvent*>::iterator it = list.begin(), end = list.end(); it != end; ++it)
    {
        if((*it)->m_callBack == callBack)
        {
			(*it)->deleteSelf();
        }
    }
}

void Timer::removeAllTimerOf(ITimerCallBack *callBack)
{
    removeAllTimerOf(callBack, m_list);
}

void Timer::removeAllRealTimeTimerOf(ITimerCallBack *callBack)
{
    removeAllTimerOf(callBack, m_realTimeList);
}